'use strict';
let { ObjectId, MongoClient } = require('mongodb');

module.exports = function initMongoDB(config) {
  config || (config = {});
  // init MongoDB
  return new Promise((resolve) => {
    MongoClient.connect(`mongodb://${config.host || '127.0.0.1'}:${config.port || 27017}/${config.db || 'wonder_list'}`, (err, db) => {
      if (err) {
        throw err;
      }
      global.db = db;
      global.ObjectId = ObjectId;
      resolve(db);
    });
  });
};

global.mongo = {
  find: (collection, params) => {
    params || (params = {});
    if (params.limit) {
      return collection.find(params.query || {}, params.fileds || {}, params.options || {}).sort(params.sort || {}).skip(parseInt(params.skip || 0)).limit(parseInt(params.limit)).toArray();
    } else {
      return collection.find(params.query || {}, params.fileds || {}, params.options || {}).sort(params.sort || {}).skip(parseInt(params.skip || 0)).toArray();
    }
  },
  findOne: (collection, params) => {
    return collection.findOne(params.query, params.fileds || {}, params.option || {});
  },
  findOneByObjectId: (collection, _id, fileds) => {
    return collection.findOne({
      _id: new ObjectId(_id)
    }, fileds);
  },
  flip: (collection, params) => {
    let index = {};

    if (params.index) {
      let key = Object.keys(params.index)[0];
      index[key] = { '$gt': params.index[key] };
    }
    return collection.find(params.query || {}, params.model || {}, index).sort(params.sort || {}).limit(params.limit).toArray();
  },
  insert: (collection, params) => {
    return collection.insertMany(params.data, params.option || {});
  },
  insertOne: (collection, params) => {
    return collection.insertOne(params);
  },
  update: (collection, params) => {
    return collection.updateMany(params.query, params.options || {}, {
      $set: params.data
    },
      {
        // upsert: true,
        returnOriginal: true
      });
  },
  updateOne: (collection, params) => {
    return collection.updateOne(params.query, {
      $set: params.data
    },
      {
        // upsert: true,
        returnOriginal: true
      });
  },
  updateOneByObjectId: (collection, params) => {
    return collection.updateOne({
      _id: new ObjectId(params._id)
    },
      {
        $set: params.data
      }, {
        // upsert: true,
        returnOriginal: true
      });
  },
  findOneAndUpdate: (collection, params) => {
    return collection.findOneAndUpdate(params.query, {
      $set: params.data
    },
      {
        // upsert: true,
        returnOriginal: true
      });
  },
  findOneAndUpdateByObjectId: (collection, params) => {
    return collection.findOneAndUpdate({
      _id: new ObjectId(params._id)
    },
      {
        $set: params.data
      },
      {
        // upsert: true,
        returnOriginal: true
      });
  },
  delete: (collection, params) => {
    return collection.deleteMany(params.query, params.option || {});
  },
  deleteOne: (collection, params) => {
    return collection.findOneAndDelete(params.query, params.option || {});
  },
  deleteOneByObjectId: (collection, _id) => {
    return collection.findOneAndDelete({
      _id: new ObjectId(_id)
    });
  },
  count: (collection, params) => {
    return collection.count(params || {});
  },
  drop: (collection) => {
    return collection.drop();
  },
  removeAll: (collection) => {
    return collection.removeMany();
  },
  remove: (collection, params) => {
    return collection.removeMany(params.query, params.option || {});
  },
  removeOne: (collection, params) => {
    return collection.removeOne(params.query, params.option || {});
  },
  removeOneByObjectId: (collection, _id) => {
    return collection.removeOne({
      _id: new ObjectId(_id)
    });
  }
};
